import os
import sys
import shutil
import subprocess
import datetime
from pathlib import Path

def install_pyinstaller():
    """确保PyInstaller已安装"""
    try:
        import PyInstaller
        print("PyInstaller已安装")
    except ImportError:
        print("正在安装PyInstaller...")
        subprocess.check_call([sys.executable, "-m", "pip", "install", "PyInstaller"])
        print("PyInstaller安装完成")

def install_dependencies():
    """确保必要的依赖已安装"""
    print("检查并安装必要的依赖...")
    
    # 读取requirements.txt文件
    if os.path.exists("requirements.txt"):
        try:
            # 直接逐行读取requirements.txt文件，避免编码问题
            with open("requirements.txt", "r", encoding="utf-8") as f:
                requirements = [line.strip() for line in f if line.strip() and not line.strip().startswith('#')]
            
            # 逐个安装依赖，而不是使用-r参数
            for req in requirements:
                try:
                    print(f"安装依赖: {req}")
                    subprocess.check_call([sys.executable, "-m", "pip", "install", req])
                except subprocess.CalledProcessError as e:
                    print(f"警告: 安装 {req} 失败: {e}")
        except Exception as e:
            print(f"读取requirements.txt文件时出错: {e}")
    
    # 确保Prophet和相关依赖已安装
    try:
        import prophet
        print("Prophet已安装")
    except ImportError:
        print("正在安装Prophet及其依赖...")
        try:
            subprocess.check_call([sys.executable, "-m", "pip", "install", "prophet"])
            print("Prophet安装完成")
        except subprocess.CalledProcessError as e:
            print(f"警告: 安装Prophet失败: {e}")
            print("将继续使用模拟的Prophet模块")
    
    # 确保其他数据分析库已安装
    dependencies = ["pandas", "numpy", "matplotlib", "plotly"]
    for dep in dependencies:
        try:
            __import__(dep)
            print(f"{dep}已安装")
        except ImportError:
            print(f"正在安装{dep}...")
            try:
                subprocess.check_call([sys.executable, "-m", "pip", "install", dep])
                print(f"{dep}安装完成")
            except subprocess.CalledProcessError as e:
                print(f"警告: 安装{dep}失败: {e}")
    
    print("所有依赖检查完成")

def create_spec_file(simple_mode=False):
    """创建PyInstaller规范文件
    
    Args:
        simple_mode: 如果为True，则使用简化模式打包，不包含复杂依赖
    """
    
    # 首先确保prophet补丁文件存在
    if not os.path.exists("scripts/prophet_patch.py"):
        shutil.copy2("scripts/prophet_patch.py", "scripts/prophet_patch.py")
    
    # 创建入口点文件
    if not os.path.exists("scripts/app_entry.py"):
        shutil.copy2("scripts/app_entry.py", "scripts/app_entry.py")
    
    # 准备内容
    content_lines = []
    content_lines.append("# -*- mode: python ; coding: utf-8 -*-")
    content_lines.append("import os")
    content_lines.append("import sys")
    content_lines.append("import site")
    content_lines.append("from pathlib import Path")
    content_lines.append("")
    content_lines.append("block_cipher = None")
    content_lines.append("")
    
    # 添加Prophet相关代码
    if simple_mode:
        content_lines.append("# 简化模式，不查找Prophet模块")
        content_lines.append("prophet_datas = []")
    else:
        content_lines.append("# 查找和添加prophet相关文件")
        content_lines.append("prophet_datas = []")
        content_lines.append("try:")
        content_lines.append("    import prophet")
        content_lines.append("    prophet_dir = os.path.dirname(prophet.__file__)")
        content_lines.append("    # 添加prophet目录本身")
        content_lines.append("    prophet_datas.append((prophet_dir, 'prophet'))")
        content_lines.append("    # 检查__version__.py文件是否存在")
        content_lines.append("    version_file = os.path.join(prophet_dir, '__version__.py')")
        content_lines.append("    if os.path.exists(version_file):")
        content_lines.append("        # 添加为单独的data文件以确保它被包含")
        content_lines.append("        prophet_datas.append((version_file, 'prophet'))")
        content_lines.append("    else:")
        content_lines.append("        # 如果在临时目录中有版本文件，使用它")
        content_lines.append("        temp_version_file = os.path.join('temp_prophet_files', '__version__.py')")
        content_lines.append("        if os.path.exists(temp_version_file):")
        content_lines.append("            prophet_datas.append((temp_version_file, 'prophet'))")
        content_lines.append("except ImportError:")
        content_lines.append("    print(\"警告: 无法导入prophet模块\")")
    
    content_lines.append("")
    content_lines.append("# 添加补丁文件")
    content_lines.append("patch_datas = [")
    content_lines.append("    ('scripts/prophet_patch.py', 'scripts')")
    content_lines.append("]")
    content_lines.append("")
    
    # 添加Analysis部分
    content_lines.append("a = Analysis(")
    content_lines.append("    ['scripts/app_entry.py'],  # 使用新的入口点")
    content_lines.append("    pathex=[],")
    content_lines.append("    binaries=[],")
    content_lines.append("    datas=[")
    content_lines.append("        ('app/templates', 'app/templates'),")
    content_lines.append("        ('app/static', 'app/static'),")
    content_lines.append("        ('app.py', '.'),  # 添加原始app.py")
    content_lines.append("    ] + prophet_datas + patch_datas,")
    content_lines.append("    hiddenimports=[")
    
    # 添加hiddenimports
    if simple_mode:
        content_lines.append("        'flask_sqlalchemy',")
        content_lines.append("        'flask_migrate',")
        content_lines.append("        'flask_login',")
        content_lines.append("        'flask_wtf',")
        content_lines.append("        'wtforms',")
        content_lines.append("        'jinja2',")
        content_lines.append("        'sqlalchemy',")
        content_lines.append("        'pandas',")
        content_lines.append("        'numpy',")
        content_lines.append("        'matplotlib',")
        content_lines.append("        'scripts.prophet_patch'")
    else:
        content_lines.append("        'flask_sqlalchemy',")
        content_lines.append("        'flask_migrate',")
        content_lines.append("        'flask_login',")
        content_lines.append("        'flask_wtf',")
        content_lines.append("        'wtforms',")
        content_lines.append("        'jinja2',")
        content_lines.append("        'sqlalchemy',")
        content_lines.append("        'prophet',")
        content_lines.append("        'prophet.forecaster',")
        content_lines.append("        'prophet.serialize',")
        content_lines.append("        'prophet.models',")
        content_lines.append("        'plotly',")
        content_lines.append("        'pandas',")
        content_lines.append("        'numpy',")
        content_lines.append("        'matplotlib',")
        content_lines.append("        'holidays',")
        content_lines.append("        'cython',")
        content_lines.append("        'cmdstanpy',")
        content_lines.append("        'pystan',")
        content_lines.append("        'scripts.prophet_patch'")
    
    content_lines.append("    ],")
    content_lines.append("    hookspath=[],")
    content_lines.append("    hooksconfig={},")
    content_lines.append("    runtime_hooks=[],")
    content_lines.append("    excludes=[],")
    content_lines.append("    win_no_prefer_redirects=False,")
    content_lines.append("    win_private_assemblies=False,")
    content_lines.append("    cipher=block_cipher,")
    content_lines.append("    noarchive=False,")
    content_lines.append(")")
    content_lines.append("")
    
    # 添加额外文件复制代码
    content_lines.append("# 额外复制Prophet相关文件")
    content_lines.append("for site_path in site.getsitepackages():")
    content_lines.append("    prophet_path = Path(site_path) / 'prophet'")
    
    if simple_mode:
        content_lines.append("    if prophet_path.exists() and False:  # 简化模式下不执行")
    else:
        content_lines.append("    if prophet_path.exists():  # 完整模式下执行")
    
    content_lines.append("        for item in prophet_path.glob('**/*'):")
    content_lines.append("            if item.is_file():")
    content_lines.append("                rel_path = item.relative_to(site_path)")
    content_lines.append("                a.datas += [(str(rel_path), str(item), 'DATA')]")
    content_lines.append("")
    
    # 添加PYZ和EXE部分
    content_lines.append("pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)")
    content_lines.append("")
    content_lines.append("exe = EXE(")
    content_lines.append("    pyz,")
    content_lines.append("    a.scripts,")
    content_lines.append("    a.binaries,")
    content_lines.append("    a.zipfiles,")
    content_lines.append("    a.datas,")
    content_lines.append("    [],")
    content_lines.append("    name='妙趣拾光盒管理系统',")
    content_lines.append("    debug=False,")
    content_lines.append("    bootloader_ignore_signals=False,")
    content_lines.append("    strip=False,")
    content_lines.append("    upx=True,")
    content_lines.append("    upx_exclude=[],")
    content_lines.append("    runtime_tmpdir=None,")
    content_lines.append("    console=True,")
    content_lines.append("    disable_windowed_traceback=False,")
    content_lines.append("    argv_emulation=False,")
    content_lines.append("    target_arch=None,")
    content_lines.append("    codesign_identity=None,")
    content_lines.append("    entitlements_file=None,")
    content_lines.append("    icon='app/static/img/favicon.ico' if os.path.exists('app/static/img/favicon.ico') else None,")
    content_lines.append(")")
    
    # 写入文件
    with open("box_admin.spec", "w", encoding="utf-8") as f:
        f.write("\n".join(content_lines))
    
    print("创建规范文件成功")

def build_executable():
    """使用PyInstaller构建可执行文件"""
    print("开始构建可执行文件...")
    
    # 清理旧的构建文件
    if os.path.exists("build"):
        shutil.rmtree("build")
    
    if os.path.exists("dist"):
        for item in os.listdir("dist"):
            if item.endswith(".exe"):
                os.remove(os.path.join("dist", item))
    
    # 尝试创建Prophet的模拟模块，以解决可能的导入问题
    try:
        # 检查是否存在prophet模块
        import prophet
        print("检测到Prophet模块，使用已安装的Prophet")
    except ImportError:
        print("未检测到Prophet模块，创建模拟模块...")
        
        # 创建临时模块目录
        mock_dir = "temp_mock_modules"
        if os.path.exists(mock_dir):
            shutil.rmtree(mock_dir)
        os.makedirs(os.path.join(mock_dir, "prophet"))
        
        # 创建__init__.py
        with open(os.path.join(mock_dir, "prophet", "__init__.py"), "w") as f:
            f.write("# 模拟Prophet模块\n")
            f.write("__version__ = '1.0.0'\n")
            f.write("print('使用模拟的Prophet模块')\n")
        
        # 创建__version__.py
        with open(os.path.join(mock_dir, "prophet", "__version__.py"), "w") as f:
            f.write("__version__ = '1.0.0'\n")
        
        # 将模拟模块添加到系统路径
        sys.path.insert(0, mock_dir)
        print(f"已创建模拟Prophet模块: {os.path.join(mock_dir, 'prophet')}")
    
    # 执行PyInstaller
    subprocess.check_call([
        sys.executable, 
        "-m", 
        "PyInstaller", 
        "box_admin.spec", 
        "--clean"
    ])
    
    # 清理临时目录
    if os.path.exists("temp_prophet_files"):
        shutil.rmtree("temp_prophet_files")
    if os.path.exists("temp_mock_modules"):
        shutil.rmtree("temp_mock_modules")
    
    print("构建完成")

def create_release_package():
    """创建一个发布包，包含可执行文件和相关文档"""
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    release_dir = f"release_v{timestamp}"
    
    if not os.path.exists(release_dir):
        os.makedirs(release_dir)
    
    # 复制可执行文件
    exe_path = list(Path("dist").glob("*.exe"))
    if exe_path:
        shutil.copy2(exe_path[0], os.path.join(release_dir, exe_path[0].name))
    
    # 复制README
    if os.path.exists("README.md"):
        shutil.copy2("README.md", os.path.join(release_dir, "使用说明.md"))
    
    # 创建启动说明文件
    with open(os.path.join(release_dir, "运行说明.txt"), "w", encoding="utf-8") as f:
        f.write("妙趣拾光盒管理系统启动说明\n\n")
        f.write("1. 直接双击\"妙趣拾光盒管理系统.exe\"即可启动应用\n")
        f.write("2. 启动后，在浏览器中访问 http://127.0.0.1:5000\n")
        f.write("3. 使用以下默认账号登录：\n")
        f.write("   - 用户名：admin\n")
        f.write("   - 密码：admin\n\n")
        f.write("注意：首次启动可能需要等待几秒钟\n")
    
    print(f"发布包已创建在 {release_dir} 目录")
    return release_dir

def main():
    # 确保在项目根目录
    if not os.path.exists("app.py"):
        print("错误：请在项目根目录运行此脚本")
        sys.exit(1)
    
    # 检查是否使用简化模式
    use_simple_mode = len(sys.argv) > 1 and sys.argv[1] == '--simple'
    
    if use_simple_mode:
        print("使用简化模式打包，将不包含Prophet相关依赖")
    
    try:
        # 安装PyInstaller
        install_pyinstaller()
        
        # 安装所需依赖
        install_dependencies()
        
        # 创建规范文件
        create_spec_file(simple_mode=use_simple_mode)
        
        # 构建可执行文件
        build_executable()
        
        # 创建发布包
        release_dir = create_release_package()
        
        print(f"\n打包成功！请在 {release_dir} 目录找到可执行文件。")
        print("双击\"妙趣拾光盒管理系统.exe\"即可启动应用程序。")
        
    except Exception as e:
        print(f"打包过程中出错：{str(e)}")
        sys.exit(1)

if __name__ == "__main__":
    main() 